package com.ctakit.proxy.asm;

import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_SUPER;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.RETURN;
import static org.objectweb.asm.Opcodes.V1_8;

import java.lang.reflect.InvocationTargetException;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import com.ctakit.util.FileUtils;

import net.sf.cglib.core.ReflectUtils;

/**
 * 使用ASM实现AOP功能
 */
public class ASMAop {
	public static void main(String[] args) throws Exception {
		test2();

	}

	public static void test2() throws Exception {
		
		
		
		/**
		 * 
		 * 
		 * 
		Log.startLog();
		System.out.println("***********这里是dosomething执行的逻辑**********");
		Log.endLog();
		 */

		ClassReader cr = new ClassReader("com.ctakit.proxy.asm.Operation");
		ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		cr.accept(new LogClassVisitor(cw), ClassReader.SKIP_DEBUG);
		
		
		
		MyClassLoader myClassLoader = new MyClassLoader();
		Thread.currentThread().setContextClassLoader(myClassLoader);
		Class<?> clazz = myClassLoader.defineClassForName("com.ctakit.proxy.asm.Operation", cw.toByteArray());

		// clazz.getMethods()[0].invoke(clazz.newInstance());
		 //Operation o = (Operation)clazz.newInstance() ;
		
		
		//Class<?> testAopClass = ReflectUtils.defineClass("com.ctakit.proxy.asm.TestAop", FileUtils.classToBytes(TestAop.class), myClassLoader);
		Class<?> testAopClass = myClassLoader.defineClassForName("com.ctakit.proxy.asm.TestAop", FileUtils.classToBytes(TestAop.class));
		
		

		testAopClass.getMethods()[0].invoke(testAopClass.newInstance());
	}

	public static void test() {
		{
			ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
			cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "com/ctakit/proxy/asm/test", null, "java/lang/Object", null);
			// 方法开始init
			MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
			mv.visitCode();

			mv.visitVarInsn(ALOAD, 0);
			mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
			mv.visitInsn(RETURN);
			Label l1 = new Label();
			mv.visitLabel(l1);
			mv.visitMaxs(1, 1);
			mv.visitEnd();// 方法init结束

			mv = cw.visitMethod(ACC_PUBLIC, "oper", "()V", null, null);
			mv.visitCode();
			mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
			mv.visitLdcInsn("***********\u8fd9\u91cc\u662foper\u6267\u884c\u7684\u903b\u8f91**********");
			mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

			mv.visitInsn(RETURN);
			mv.visitMaxs(2, 1);
			mv.visitEnd();
			MyClassLoader myClassLoader = new MyClassLoader();

			Class<?> clazz = myClassLoader.defineClassForName("com.ctakit.proxy.asm.test", cw.toByteArray());

			try {
				clazz.getMethods()[0].invoke(clazz.newInstance());
			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException
					| InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}
}

class MyClassLoader extends ClassLoader {
	public MyClassLoader() {
		super(Thread.currentThread().getContextClassLoader());
	}

	public Class<?> defineClassForName(String name, byte[] data) {
		return this.defineClass(name, data, 0, data.length);
	}
}